package fr.lip6.meta.ple.generation.strategy;

import java.util.Iterator;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.gmt.modisco.java.AnonymousClassDeclaration;
import org.eclipse.gmt.modisco.java.ArrayAccess;
import org.eclipse.gmt.modisco.java.ArrayCreation;
import org.eclipse.gmt.modisco.java.ArrayInitializer;
import org.eclipse.gmt.modisco.java.ArrayLengthAccess;
import org.eclipse.gmt.modisco.java.BodyDeclaration;
import org.eclipse.gmt.modisco.java.BooleanLiteral;
import org.eclipse.gmt.modisco.java.CastExpression;
import org.eclipse.gmt.modisco.java.CatchClause;
import org.eclipse.gmt.modisco.java.CharacterLiteral;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.ClassInstanceCreation;
import org.eclipse.gmt.modisco.java.ConditionalExpression;
import org.eclipse.gmt.modisco.java.ConstructorDeclaration;
import org.eclipse.gmt.modisco.java.Expression;
import org.eclipse.gmt.modisco.java.ExpressionStatement;
import org.eclipse.gmt.modisco.java.FieldDeclaration;
import org.eclipse.gmt.modisco.java.ForStatement;
import org.eclipse.gmt.modisco.java.IfStatement;
import org.eclipse.gmt.modisco.java.InfixExpression;
import org.eclipse.gmt.modisco.java.InstanceofExpression;
import org.eclipse.gmt.modisco.java.InterfaceDeclaration;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.java.MethodInvocation;
import org.eclipse.gmt.modisco.java.Model;
import org.eclipse.gmt.modisco.java.Modifier;
import org.eclipse.gmt.modisco.java.NamedElement;
import org.eclipse.gmt.modisco.java.NullLiteral;
import org.eclipse.gmt.modisco.java.PostfixExpression;
import org.eclipse.gmt.modisco.java.PrefixExpression;
import org.eclipse.gmt.modisco.java.ReturnStatement;
import org.eclipse.gmt.modisco.java.SingleVariableDeclaration;
import org.eclipse.gmt.modisco.java.Statement;
import org.eclipse.gmt.modisco.java.ThisExpression;
import org.eclipse.gmt.modisco.java.TryStatement;
import org.eclipse.gmt.modisco.java.TypeAccess;
import org.eclipse.gmt.modisco.java.UnresolvedItemAccess;
import org.eclipse.gmt.modisco.java.VariableDeclarationExpression;
import org.eclipse.gmt.modisco.java.VariableDeclarationFragment;
import org.eclipse.gmt.modisco.java.VariableDeclarationStatement;
import org.eclipse.gmt.modisco.java.WhileStatement;
import org.eclipse.gmt.modisco.java.emf.JavaPackage;
import org.eclipse.gmt.modisco.java.emf.impl.ArrayAccessImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ArrayCreationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ArrayInitializerImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ArrayLengthAccessImpl;
import org.eclipse.gmt.modisco.java.emf.impl.AssignmentImpl;
import org.eclipse.gmt.modisco.java.emf.impl.BlockImpl;
import org.eclipse.gmt.modisco.java.emf.impl.CastExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.CatchClauseImpl;
import org.eclipse.gmt.modisco.java.emf.impl.CharacterLiteralImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ConditionalExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ConstructorDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ExpressionStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldAccessImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ForStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.IfStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.InfixExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.InstanceofExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.MethodInvocationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.NumberLiteralImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ParenthesizedExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ReturnStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.SingleVariableAccessImpl;
import org.eclipse.gmt.modisco.java.emf.impl.StringLiteralImpl;
import org.eclipse.gmt.modisco.java.emf.impl.TryStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.TypeAccessImpl;
import org.eclipse.gmt.modisco.java.emf.impl.TypeDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.VariableDeclarationExpressionImpl;
import org.eclipse.gmt.modisco.java.emf.impl.VariableDeclarationFragmentImpl;
import org.eclipse.gmt.modisco.java.emf.impl.VariableDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.VariableDeclarationStatementImpl;
import org.eclipse.gmt.modisco.java.emf.impl.WhileStatementImpl;

import fr.lip6.meta.ple.generation.ItemInstanceNotFound;

public abstract class ReadXmiStrategy implements GenerationStrategy {
	/**
	 * @param methodDecl
	 * @return
	 */
	public abstract String getMethodDeclarationText(MethodDeclaration methodDecl);

	/**
	 * @param methodDecl
	 * @return
	 */
	public abstract String getMethodDeclarationAndBodyText(MethodDeclaration methodDecl);

	/**
	 * @param consDecl
	 * @return
	 */
	public abstract String getConstructorDeclarationText(ConstructorDeclaration consDecl);

	/**
	 * @param consDecl
	 * @return
	 */
	public abstract String getConstructorDeclarationAndBodyText(ConstructorDeclaration consDecl);

	public static Resource loadJavaModel(String path) {
		ResourceSet rs;
		URI uri;
		XMIResourceImpl resource;

		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
				"*",
				new XMIResourceFactoryImpl());

		rs = new ResourceSetImpl();
		uri = URI.createFileURI(path);
		rs.getPackageRegistry().put(JavaPackage.eNS_URI,
				JavaPackage.eINSTANCE);
		resource = (XMIResourceImpl) rs.getResource(uri, true);

		return resource;
	}

	/**
	 * reads xmi file and gets model from this file
	 * @param path
	 * @return
	 */
	public Model loadModiscoJavaModel(String path) {
		Resource resource = loadJavaModel(path);
		Model model = (Model) resource.getContents().get(0);

		return model;
	}

	/**
	 * Gets the class declaration and body 
	 * @param classDecl
	 * @return
	 */
	public String getClassDeclarationAndBodyText(ClassDeclaration classDecl, boolean refine) {
		StringBuilder res = new StringBuilder();
		EList<BodyDeclaration> bodyDecls;
		boolean	fieldPrev = false,
				consPrev = false,
				methodPrev = false;

		res.append(getClassDeclarationText(classDecl, refine));
		res.append(" {\n");

		bodyDecls = classDecl.getBodyDeclarations();

		//read body declaration 
		for(BodyDeclaration bobyDecl : bodyDecls) {
			if (bobyDecl instanceof FieldDeclarationImpl) {
				FieldDeclarationImpl fieldDecl = (FieldDeclarationImpl) bobyDecl;

				if (consPrev || methodPrev)
					res.append("\n");

				res.append(getFieldDeclarationText(fieldDecl));

				fieldPrev = true;
				consPrev = false;
				methodPrev = false;
			}

			if (bobyDecl instanceof ConstructorDeclaration) {
				ConstructorDeclarationImpl consDecl = (ConstructorDeclarationImpl) bobyDecl;
				
				if (fieldPrev || methodPrev)
					res.append("\n\n");
				else
					res.append("\n");

				res.append(getConstructorDeclarationAndBodyText(consDecl));
				
				//System.out.println(consDecl.getName()+" parameters: "+consDecl.getParameters());

				consPrev = true;
				fieldPrev = false;
				methodPrev = false;
			}

			if (bobyDecl instanceof MethodDeclaration) {
				MethodDeclaration methodDecl = (MethodDeclaration) bobyDecl;

				if (fieldPrev || consPrev)
					res.append("\n\n");
				else
					res.append("\n");

				res.append(getMethodDeclarationAndBodyText(methodDecl));

				methodPrev = true;
				fieldPrev = false;
				consPrev = false;
			}

			res.append("\n");
		}

		res.append("\n}");

		return res.toString();
	}

	public static String getClassDeclarationText(ClassDeclaration clDecl, boolean refine) {
		StringBuilder str = new StringBuilder();
		TypeAccess tp = clDecl.getSuperClass();
		EList<TypeAccess> supinterfaces = clDecl.getSuperInterfaces();
		int i = 0;

		str.append(getDeclarationModifierTextWithSpace((TypeDeclarationImpl) clDecl)+"class "+clDecl.getName());

		if (tp != null) {
			str.append(" extends "+tp.getType().getName()+" ");
		}

		if (supinterfaces.size() == 1) {
			TypeAccess t = supinterfaces.get(0);
			str.append(" implements "+t.getType().getName());
		} else {
			for(TypeAccess var: supinterfaces) {
				i++;

				if (i != supinterfaces.size()) {
					str.append( var.getType().getName()+ ", ");
				} else if (i == 1) {
					str.append(" implements "+ var.getType().getName()+" ");
				} else {
					str.append( var.getType().getName()+"");
				}
			}
		}

		return str.toString();
	}

	public String getAnonymousClassText(AnonymousClassDeclaration classDecl) {
		StringBuilder res = new StringBuilder();
		EList<BodyDeclaration> bodyDecls;
		boolean	fieldPrev = false,
				methodPrev = false;

		res.append(" {\n");

		bodyDecls = classDecl.getBodyDeclarations();

		//read body declaration 
		for(BodyDeclaration bobyDecl : bodyDecls) {
			if (bobyDecl instanceof FieldDeclarationImpl) {
				FieldDeclarationImpl fieldDecl = (FieldDeclarationImpl) bobyDecl;

				if (methodPrev)
					res.append("\n");

				res.append("\t"+getFieldDeclarationText(fieldDecl));

				fieldPrev = true;
				methodPrev = false;
			}

			if (bobyDecl instanceof ConstructorDeclaration) {
				/* only default constructor is here */
			}

			if (bobyDecl instanceof MethodDeclaration) {
				MethodDeclaration methodDecl = (MethodDeclaration) bobyDecl;

				if (fieldPrev)
					res.append("\n\n");
				else
					res.append("\n");

				res.append("\t"+getMethodDeclarationAndBodyText(methodDecl));

				methodPrev = true;
				fieldPrev = false;
			}

			res.append("\n");
		}

		res.append("\n\t\t}");

		return res.toString();
	}
	
	public String readBlock(BlockImpl b) {
		StringBuilder str = new StringBuilder();

		for(Statement st : b.getStatements()) {
			str.append(getStatement(st)+"\n");
		}

		return str.toString();
	}

	public String getStatement(Statement st) {
		String res = "";

		if (st instanceof ExpressionStatement) {
			ExpressionStatementImpl es = (ExpressionStatementImpl) st;
			res += readExpressionStatement(es);
		}

		if(st instanceof ReturnStatement) {
			ReturnStatementImpl es = (ReturnStatementImpl) st;
			res += getReturnStatementBody((ReturnStatement) es);
		}

		if(st instanceof IfStatement) {
			IfStatementImpl ifs = (IfStatementImpl) st;
			res += readIfStatement(ifs);
		}

		if(st instanceof ForStatement) {
			ForStatementImpl f = (ForStatementImpl) st;
			res += getForStatementBody(f);
		}

		if(st instanceof WhileStatement) {
			WhileStatementImpl w = (WhileStatementImpl) st;
			res += getWhileDeclarationAndBodyText(w);
		}

		if(st instanceof TryStatement) {
			TryStatementImpl tr = (TryStatementImpl) st;
			res += getTryStatement(tr);
		}

		if(st instanceof VariableDeclarationStatement)
		{
			VariableDeclarationStatementImpl var = (VariableDeclarationStatementImpl) st;	
			res += getVariableDeclarationStatement(var);
		}

		return res;
	}

	String getForStatementBody(ForStatement f) {
		StringBuilder strBldr = new StringBuilder();
		BlockImpl rst;

		strBldr.append("for(");

		for(Expression ex : f.getInitializers()) {
			strBldr.append(readExpression(ex));
		}

		strBldr.append("; ");	
		strBldr.append(readExpression(f.getExpression()));	
		strBldr.append("; ");

		for(Expression ex : f.getUpdaters()) {
			strBldr.append(readExpression(ex));	
		}

		strBldr.append(") {\n");
		rst = (BlockImpl) f.getBody();

		for(Statement st : rst.getStatements()) {
			strBldr.append(getStatement(st));
			strBldr.append("\n");
		}

		return strBldr.toString()+"}";
	}

	String getWhileDeclarationAndBodyText(WhileStatementImpl w) {
		StringBuilder str = new StringBuilder();
		Statement body = w.getBody();

		str.append("while("+readExpression(w.getExpression())+") {\n");

		if (body instanceof ExpressionStatementImpl) {
			str.append(getStatement(w.getBody()));
			str.append("\n");
		} else if (body instanceof BlockImpl) {
			str.append(readBlock((BlockImpl) body));
		}

		return str.toString()+"}";
	}

	String getVariableDeclarationStatement(VariableDeclarationStatement vd) {
		StringBuilder strBuilder = new StringBuilder();
		String type = readExpression(vd.getType());
		EList<VariableDeclarationFragment> vars = vd.getFragments();
		
		strBuilder.append(
				"\t\t"
			+	getVariableStatementModifierTextWithSpace((VariableDeclarationStatementImpl) vd)
			+	type + " ");
		
		for(VariableDeclarationFragment var : vars) {
			strBuilder.append(readNamedElement(var) + ", ");
		}

		return strBuilder.substring(0, strBuilder.length()-2)+";";
	}

	String getReturnStatementBody(ReturnStatement es) {
		org.eclipse.gmt.modisco.java.
		Expression ex= es.getExpression();

		return "return "+ readExpression(ex)+";";
	}

	public String getInterfaceBody(InterfaceDeclaration c, boolean refine) {
		StringBuilder res = new StringBuilder();

		res.append(getInterfaceDeclaration(c,refine)+"\n");
		EList<BodyDeclaration> bodies = c.getBodyDeclarations();
		//read body declaration
		for(BodyDeclaration bo : bodies) {
			if (bo instanceof MethodDeclaration) {
				MethodDeclaration m= (MethodDeclaration) bo;
				res.append(getInterfaceMethodDeclaration(m));
			}
		}

		res.append("\n}\n");

		return res.toString();
	}

	public static String getInterfaceDeclaration(InterfaceDeclaration interDecl, boolean refine)
	{
		StringBuilder str=new StringBuilder();

		/*EList<TypeAccess> supinterfaces=*/interDecl.getSuperInterfaces();
		str.append(getInterfaceModifierTextWithSpace(interDecl) +"interface  "+interDecl.getName()+" { \n");
		return str.toString();
	}

	static String getInterfaceMethodDeclaration(MethodDeclaration m) {
		StringBuilder res = new StringBuilder();

		if(m != null) {
			String vis = getMethodModifierTextWithSpace(m);
			String returntype = m.getReturnType().getType().getName();
			EList<SingleVariableDeclaration> parmetres = m.getParameters();
			String method = vis+returntype+" "+m.getName()+"(";
			int i = 0;

			if(parmetres.size() == 0) {
				method += ")";
			} else {
				for(SingleVariableDeclaration var: parmetres) {
					i++;
					
					if(i!=parmetres.size()) {
						method+=var.getType().getType().getName() +" "+var.getName()+",";
					} else {
						method+=var.getType().getType().getName() +" "+var.getName()+")";
					}
				}
			}
			
			res.append(method+";\n");
		}
		
		return res.toString();
	}

	String getTryStatement(TryStatement f) {
		StringBuilder str = new StringBuilder();

		str.append("try {");

		BlockImpl rst = (BlockImpl) f.getBody();

		for(Statement st : rst.getStatements()) {
			str.append(getStatement(st));
			str.append("\n");
		}

		str.append("} ");

		Iterator<CatchClause> catchecluses = f.getCatchClauses().iterator();

		while(catchecluses.hasNext()) {
			CatchClauseImpl c = (CatchClauseImpl) catchecluses.next();
			SingleVariableDeclaration sin = c.getException();
			String res = sin.getType().getType().getName() +" "+sin.getName();
			String s = "catch("+res+") {\n";
			str.append(s);
			str.append(getCatchStatementBody(c)+"\n");
		}

		BlockImpl b = (BlockImpl) f.getFinally();

		if(b != null) {
			str.append("finally {\n");
			str.append(readBlock(b));
			str.append("}");
		}

		return str.toString();
	}

	String getCatchStatementBody(CatchClauseImpl catchcluse) {
		StringBuilder str = new StringBuilder();

		BlockImpl rst = (BlockImpl) catchcluse.getBody();

		for(Statement st : rst.getStatements()) {
			str.append(getStatement(st));
			str.append("\n");
		}

		return str.toString()+"\n}";
	}

	public String getFieldDeclarationText(FieldDeclarationImpl fd) {
		EList<VariableDeclarationFragment> fields = fd.getFragments();
		String fieldDeclText	=	"\t"+getFieldModifierTextWithSpace(fd)
								+	fd.getType().getType().getName() + " ";
		
		for(VariableDeclarationFragment field : fields) {
			fieldDeclText += readNamedElement(field) + ", ";
		}
		
		return fieldDeclText.substring(0, fieldDeclText.length()-2)+";";
	}

	String readExpressionStatement(ExpressionStatement es) {
		String res = "";
		Expression ii = es.getExpression();

		res = readExpression(ii);

		return res+";";
	}

	public String readExpression(Expression expr) {
		String res = "";

		if (expr instanceof InfixExpression) {
			InfixExpressionImpl res1 = (InfixExpressionImpl) expr;
			String lef = "";
			String r = "";

			lef = readExpression(res1.getLeftOperand());
			r = readExpression(res1.getRightOperand());

			res = lef+" "+res1.getOperator()+" "+r;
		} else

		if (expr instanceof PrefixExpression) {
			PrefixExpression res1 = (PrefixExpression) expr;

			res = res1.getOperator().getLiteral() + readExpression(res1.getOperand());
		} else
		
		if (expr instanceof PostfixExpression) {
			PostfixExpression pe = (PostfixExpression) expr;

			res = readExpression(pe.getOperand()) + pe.getOperator().getLiteral();
		} else

		if (expr instanceof ClassInstanceCreation) {
			ClassInstanceCreation cic = (ClassInstanceCreation) expr;
			EList<Expression> parameters;
			AnonymousClassDeclaration acd;
			int i = 0;

			res = "new "+readExpression(cic.getType())+"(";

			parameters = cic.getArguments();

			if(parameters.size() == 0) {
				res += ")";
			} else {
				for(Expression param : parameters) {
					i++;
					if(i != parameters.size()) {
						res += readExpression(param)+", ";
					} else {
						res += readExpression(param)+")";
					}
				}
			}
			
			acd = cic.getAnonymousClassDeclaration();
			
			if (acd != null) {
				res += getAnonymousClassText(acd);
			}
		} else

		if (expr instanceof AssignmentImpl) {
			AssignmentImpl res1 = (AssignmentImpl) expr;
			String l = "";
			String r = "";

			l = readExpression(res1.getLeftHandSide());
			r = readExpression(res1.getRightHandSide());

			res = l+" "+res1.getOperator()+" "+r;
		} else

		if (expr instanceof StringLiteralImpl) {
			StringLiteralImpl iii = (StringLiteralImpl) expr;
			res = iii.getEscapedValue()+"";
		} else
		
		if (expr instanceof CharacterLiteral) {
			CharacterLiteralImpl cl = (CharacterLiteralImpl) expr;
			
			res = cl.getEscapedValue();
		} else

		if (expr instanceof NumberLiteralImpl) {
			NumberLiteralImpl iii = (NumberLiteralImpl) expr;
			res = iii.getTokenValue()+"";
		} else

		if (expr instanceof FieldAccessImpl) {
			FieldAccessImpl leftside = (FieldAccessImpl) expr;
			Expression e = leftside.getExpression();

			if (e != null) {
				String s = readExpression(e);

				res = s+"."+leftside.getField().getVariable().getName();
			} else {
				res = leftside.getField().getVariable().getName();
			}
		} else

		if (expr instanceof TypeAccessImpl) {
			TypeAccessImpl ta = (TypeAccessImpl) expr;

			if (ta != null) {
				res = ta.getType().getName();
			}
		} else

		if (expr instanceof ThisExpression) {
			res = "this";
		} else

		if (expr instanceof MethodInvocation) {
			MethodInvocationImpl mo = (MethodInvocationImpl) expr;
			Expression o = mo.getExpression();
			String s = "";

			s = readExpression(mo.getExpression());

			if (o instanceof MethodInvocation) {
				s = s.replace("..", ".");
			}

			res = s;

			if (!s.equals("")) {
				res += "."+mo.getMethod().getName()+"(";
				res = res.replace("..", ".");
			} else { 
				res += ""+mo.getMethod().getName()+"(";
			}

			EList<Expression>  exs = mo.getArguments();
			int i = 0;

			for(Expression ex1 : exs) {
				if (i == 0) {
					res = res + readExpression(ex1);	
					i = 1;
				} else
					res = res  +", "+readExpression(ex1);
			}
			res = res+")";
		} else

		if (expr instanceof NullLiteral) {
			res += "null";
		} else

		if (expr instanceof UnresolvedItemAccess) {
			UnresolvedItemAccess un = (UnresolvedItemAccess) expr;

			res += un.getElement().getName();
		} else

		if (expr instanceof BooleanLiteral) {
			BooleanLiteral b1 = (BooleanLiteral) expr;

			return b1.isValue()+"";
		} else

		if (expr instanceof ParenthesizedExpressionImpl) {
			ParenthesizedExpressionImpl pa = (ParenthesizedExpressionImpl) expr;

			if(pa.getExpression() != null) {
				res = "("+readExpression(pa.getExpression())+")";
			} else {
				res = "";
			}
		} else

		if (expr instanceof InstanceofExpression) {
			InstanceofExpressionImpl in = (InstanceofExpressionImpl) expr;
			String lef = "";
			String r = "";
			lef = readExpression(in.getLeftOperand());
			r = readExpression(in.getRightOperand());
			res = lef+" instanceof "+ r;
			res = res.replace(".", "");
		} else

		if (expr instanceof CastExpression) {
			CastExpressionImpl cas = (CastExpressionImpl) expr;

			res = "("+readExpression(cas.getType())+") "+readExpression(cas.getExpression());
		} else
		
		// arrays //
		
		/*if (expr instanceof ArrayType) {
			ArrayTypeImpl at = (ArrayTypeImpl) expr;
			
			res += at.getName();
		}*/
			
		if (expr instanceof ArrayCreation) {
			ArrayCreationImpl ac = (ArrayCreationImpl) expr;
			EList<Expression> dimensions;
			int i = 0;
			String type = readExpression(ac.getType());

			res = "new "+type.substring(0, type.length()-2)+"[";

			dimensions = ac.getDimensions();

			if (dimensions.size() == 0) {
				res += "]";
			} else {
				for(Expression var : dimensions) {
					i++;
					if (i < dimensions.size()) {
						res += readExpression(var)+"][";
					} else {
						res += readExpression(var)+"]";
					}
				}
			}
		} else
		
		if (expr instanceof ArrayInitializer) {
			ArrayInitializerImpl ai = (ArrayInitializerImpl) expr;
			EList<Expression> elements = ai.getExpressions();
			
			res += "{";
			
			for(Expression elt : elements) {
				res += readExpression(elt) + ", ";
			}
			
			res = res.substring(0, res.length()-2) + "}";
		} else
		
		if (expr instanceof ArrayLengthAccess) {
			ArrayLengthAccessImpl ala = (ArrayLengthAccessImpl) expr;

			res = readExpression(ala.getArray()) + ".length";
		} else
		
		if (expr instanceof ArrayAccess) {
			ArrayAccessImpl aa = (ArrayAccessImpl) expr;

			res = readExpression(aa.getArray()) + "[" + readExpression(aa.getIndex()) + "]";
		} else
		
		// variables //
		
		if (expr instanceof SingleVariableAccessImpl) {
			SingleVariableAccessImpl leftside = (SingleVariableAccessImpl) expr;

			if(leftside.getQualifier() != null) {
				res = readExpression(leftside.getQualifier()) + "." + leftside.getVariable().getName();
			} else {
				res = readExpression(leftside.getQualifier()) + leftside.getVariable().getName();
			}
		} else

		if (expr instanceof SingleVariableDeclaration) {
			SingleVariableDeclaration sin = (SingleVariableDeclaration) expr;
			res = sin.getType().getType().getName() + " " +sin.getName();
		} else
		
		if (expr instanceof VariableDeclarationExpression) {
			VariableDeclarationExpression vde = (VariableDeclarationExpression) expr;
			StringBuilder strBuilder = new StringBuilder();
			String modifier = getVariableExpressionModifierTextWithSpace((VariableDeclarationExpressionImpl) vde);
			String type = readExpression(vde.getType());
			EList<VariableDeclarationFragment> vars = vde.getFragments();
			
			strBuilder.append(modifier + type + " ");
			
			for(VariableDeclarationFragment var : vars) {
				strBuilder.append(readNamedElement(var) + ", ");
			}

			res = strBuilder.substring(0, strBuilder.length()-2);
		} else
		
		// others //
		
		if (expr instanceof ConditionalExpression) {
			ConditionalExpressionImpl ce = (ConditionalExpressionImpl) expr;

			res	=	readExpression(ce.getExpression())
				+	" ? " + readExpression(ce.getThenExpression())
				+	" : " + readExpression(ce.getElseExpression());
		} else if (expr == null) {
			try {
				throw new NullPointerException("expression is null");
			} catch (NullPointerException e) {
				//System.err.println(e.getMessage());
				//e.printStackTrace();
			}
		} else {
			try {
				throw new ItemInstanceNotFound("expression");
			} catch (ItemInstanceNotFound e) {
				System.err.print(expr.getClass() + ": ");
				System.err.println(e.getMessage());
				//e.printStackTrace();
			}
		}

		return res;
	}
	
	String readNamedElement(NamedElement element) {
		String res = "";
		
		if (element instanceof VariableDeclarationFragment) {
			VariableDeclarationFragmentImpl vdf = (VariableDeclarationFragmentImpl) element;
			Expression init = vdf.getInitializer();
			int ead = vdf.getExtraArrayDimensions();
			
			res += vdf.getName();
			
			for(int i=0; i<ead; i++) {
				res +=	"[]";
			}
			
			if (init != null) {
				res	+=	" = "
					+	readExpression(init);
			}
		} else if (element == null) {
			try {
				throw new NullPointerException("named element is null");
			} catch (NullPointerException e) {
				System.err.println(e.getMessage());
				//e.printStackTrace();
			}
		} else {
			try {
				throw new ItemInstanceNotFound("named element");
			} catch (ItemInstanceNotFound e) {
				System.err.print(element.getClass() + ": ");
				System.err.println(e.getMessage());
				//e.printStackTrace();
			}
		}
		
		return res;
	}

	String readIfStatement(IfStatement es) {
		StringBuilder res = new StringBuilder();

		res.append("if ("+readExpression(es.getExpression())+") {\n");

		if(es.getThenStatement() instanceof BlockImpl) {
			BlockImpl st1 = (BlockImpl) es.getThenStatement();

			res.append(readBlock(st1)+"\n}");
		} else {
			res.append(getStatement(es.getThenStatement())+"\n}");	
		}
		//
		if(es.getElseStatement() instanceof BlockImpl) {
			res.append(" else {\n");
			BlockImpl st = (BlockImpl) es.getElseStatement();
			res.append(readBlock(st));
			res.append("}");
		} else if(es.getElseStatement() == null) {

		} else {
			res.append(" else {\n");
			res.append(getStatement(es.getElseStatement()));
			res.append("\n}");
		}

		return res.toString();
	}

	
	
	public static String getDeclarationModifierTextWithSpace(TypeDeclarationImpl decl) {
		return getModifierTextWithSpace(decl.getModifier());
	}
	
	public static String getInterfaceModifierTextWithSpace(InterfaceDeclaration interDecl) {
		return getModifierTextWithSpace(interDecl.getModifier());
	}
	
	public static String getFieldModifierTextWithSpace(FieldDeclaration fieldDecl) {
		return getModifierTextWithSpace(fieldDecl.getModifier());
	}

	public static String getConstructorModifierTextWithSpace(ConstructorDeclaration consDecl) {
		return getModifierTextWithSpace(consDecl.getModifier());
	}
	
	public static String getMethodModifierTextWithSpace(MethodDeclaration methodDecl) {
		return getModifierTextWithSpace(methodDecl.getModifier());
	}
	
	public static String getVariableStatementModifierTextWithSpace(VariableDeclarationStatementImpl varDecl) {
		return getModifierTextWithSpace(varDecl.getModifier());
	}
	
	public static String getVariableExpressionModifierTextWithSpace(VariableDeclarationExpressionImpl varDecl) {
		return getModifierTextWithSpace(varDecl.getModifier());
	}
	
	private static String getModifierTextWithSpace(Modifier modifier) {
		String modifierText = "";
		String visibility = modifier.getVisibility().getName();
		String inheritance = modifier.getInheritance().getName();
		
		modifierText += visibility.equals("none") ? "" : visibility + " ";
		
		modifierText += modifier.isStatic() ? "static " : "";
		modifierText += modifier.isNative() ? "native " : "";
		modifierText += modifier.isStrictfp() ? "strictfp " : "";
		modifierText += modifier.isSynchronized() ? "synchronized " : "";
		modifierText += modifier.isTransient() ? "transient " : "";
		modifierText += modifier.isVolatile() ? "volatile " : "";
		
		modifierText += inheritance.equals("none") ? "" : inheritance + " ";
		
		return modifierText;
	}
}
